/**
 * @file   TcpClient.cpp
 * @author Djuro Drljaca (djurodrljaca@gmail.com)
 * @date   2013-05-18
 * @brief  DataBus Client using TCP socket.
 *
 * Copyright (C) 2013  Djuro Drljaca <djurodrljaca@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <DataBus/Client/TcpClient.h>

DataBus::TcpClient::TcpClient(QObject *parent)
    : AbstractClient(parent),
      m_socket()
{
}

DataBus::TcpClient::~TcpClient()
{
    // Stop client
    stop();
}

bool DataBus::TcpClient::start(const QHostAddress serverAddress,
                               const quint16 serverPort,
                               const quint8 clientId,
                               const QString &clientName,
                               const quint8 activityTimeout,
                               const quint8 pingResponseTimeout,
                               const quint8 pingRetryCount,
                               const int connectionToServerTimeout,
                               const int registrationTimeout)
{
    // Check if already registered
    if (isRegistered())
    {
        // Error, already registered
        return false;
    }

    // Check input parameters
    if (serverAddress.isNull() ||
        (serverPort == 0))
    {
        // Error, invalid input parameters
        return false;
    }

    // Initialize TCP socket
    if (m_socket.state() != QAbstractSocket::UnconnectedState)
    {
        // Error, socket must be closed before start is called
        return false;
    }

    m_socket.disconnect();

    // Connect TCP socket signals
    connect(&m_socket, SIGNAL(disconnected()),
            this, SLOT(tcpSocketDisconnected()));

    connect(&m_socket, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(tcpSocketError(QAbstractSocket::SocketError)));

    connect(&m_socket, SIGNAL(readyRead()),
            this, SLOT(readData()));

    // Connect to server
    m_socket.connectToHost(serverAddress, serverPort);

    if (m_socket.waitForConnected(connectionToServerTimeout) == false)
    {
        // Error, failed to connect to server
        m_socket.disconnect();
        return false;
    }

    // Start the Abstract Client
    if (AbstractClient::start(clientId,
                              clientName,
                              activityTimeout,
                              pingResponseTimeout,
                              pingRetryCount,
                              registrationTimeout) == false)
    {
        // Error, failed to start client
        stop();
        return false;
    }

    // Success
    return true;
}

void DataBus::TcpClient::stop()
{
    // Close the TCP socket
    if (m_socket.state() != QAbstractSocket::UnconnectedState)
    {
        m_socket.close();
    }

    // Stop Abstract Client
    AbstractClient::stop();
}

QHostAddress DataBus::TcpClient::getServerAddress() const
{
    return m_socket.peerAddress();
}

quint16 DataBus::TcpClient::getServerPort() const
{
    return m_socket.peerPort();
}

void DataBus::TcpClient::tcpSocketDisconnected()
{
    // Stop client
    stop();
}

void DataBus::TcpClient::tcpSocketError(QAbstractSocket::SocketError)
{
    stop();
}

void DataBus::TcpClient::readData()
{
    // Read available data and process it
    processReceivedData(m_socket.readAll());
}

bool DataBus::TcpClient::sendPacket(const DataBus::Packet &packet)
{
    // Check socket
    if (m_socket.state() != QAbstractSocket::ConnectedState)
    {
        // Error, socket is no connected to a server
        return false;
    }

    // Write packet data to socket
    QByteArray packetData = packet.toBinary();

    if (m_socket.write(packetData) != packetData.size())
    {
        // Error, failed to send the packet data
        return false;
    }

    // Success
    return true;
}
